package cn.iocoder.yudao.module.mqtt.controller.admin.device;

//import cn.iocoder.yudao.module.mqtt.service.MqttMessageSender;

import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.mqtt.controller.admin.device.vo.DeviceMapRespVO;
import cn.iocoder.yudao.module.mqtt.controller.admin.device.vo.DevicePageReqVO;
import cn.iocoder.yudao.module.mqtt.controller.admin.device.vo.DeviceRespVO;
import cn.iocoder.yudao.module.mqtt.controller.admin.device.vo.DeviceSaveReqVO;
import cn.iocoder.yudao.module.mqtt.controller.admin.devicelatestflow.vo.DeviceLatestFlowReqVO;
import cn.iocoder.yudao.module.mqtt.controller.admin.littree.vo.LisToken;
import cn.iocoder.yudao.module.mqtt.controller.admin.littree.vo.site.*;
import cn.iocoder.yudao.module.mqtt.controller.admin.littree.vo.site.page.LisPagesRes;
import cn.iocoder.yudao.module.mqtt.controller.admin.littree.vo.site.res.LisRes;
import cn.iocoder.yudao.module.mqtt.dal.dataobject.device.DeviceDO;
import cn.iocoder.yudao.module.mqtt.dal.dataobject.devicelatestflow.DeviceLatestFlowDO;
import cn.iocoder.yudao.module.mqtt.dal.dataobject.devicelatestlog.DeviceLatestLogDO;
import cn.iocoder.yudao.module.mqtt.framework.config.MqttProperties;
import cn.iocoder.yudao.module.mqtt.service.device.DeviceService;
import cn.iocoder.yudao.module.mqtt.service.devicelatestflow.DeviceLatestFlowService;
import cn.iocoder.yudao.module.mqtt.service.devicelatestlog.DeviceLatestLogService;
import cn.iocoder.yudao.module.mqtt.service.subscribewater.SubscribeWaterService;
import cn.iocoder.yudao.module.mqtt.util.LisTreeUtil;
import cn.iocoder.yudao.module.mqtt.util.QRCodeUtil;
import com.esotericsoftware.minlog.Log;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.annotation.security.PermitAll;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.*;

import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

@Tag(name = "管理后台 - IoT 设备")
@RestController
@RequestMapping("/mqtt/device")
@Validated
public class DeviceController {

    @Resource
    private DeviceService deviceService;
    //    @Resource
//    MqttMessageSender mqttMessageSender;
    @Autowired
    private MqttProperties mqttProperties;
    @Resource
    private SubscribeWaterService subscribeWaterService;
    @Resource
    private DeviceLatestFlowService deviceLatestService;
    @Resource
    private DeviceLatestLogService deviceLatestLogService;

    @PostMapping("/create")
    @Operation(summary = "创建IoT 设备")
    @PreAuthorize("@ss.hasPermission('mqtt:device:create')")
    public CommonResult<Long> createDevice(@Valid @RequestBody DeviceSaveReqVO createReqVO) {
        return success(deviceService.createDevice(createReqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新IoT 设备")
    @PreAuthorize("@ss.hasPermission('mqtt:device:update')")
    public CommonResult<Boolean> updateDevice(@Valid @RequestBody DeviceSaveReqVO updateReqVO) {
        deviceService.updateDevice(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除IoT 设备")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('mqtt:device:delete')")
    public CommonResult<Boolean> deleteDevice(@RequestParam("id") Long id) {
        deviceService.deleteDevice(id);
        return success(true);
    }

    @DeleteMapping("/delete-list")
    @Parameter(name = "ids", description = "编号", required = true)
    @Operation(summary = "批量删除IoT 设备")
    @PreAuthorize("@ss.hasPermission('mqtt:device:delete')")
    public CommonResult<Boolean> deleteDeviceList(@RequestParam("ids") List<Long> ids) {
        deviceService.deleteDeviceListByIds(ids);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得IoT 设备")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('mqtt:device:query')")
    public CommonResult<DeviceRespVO> getDevice(@RequestParam("id") Long id) {
        DeviceDO device = deviceService.getDevice(id);
        return success(BeanUtils.toBean(device, DeviceRespVO.class));
    }
    @GetMapping("/updateDeviceIsUpload")
    @Operation(summary = "获得IoT 设备")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('mqtt:device:query')")
    public CommonResult<DeviceRespVO> updateDeviceIsUpload(@RequestParam("id") Long id) {
        DeviceDO device = deviceService.getDevice(id);
        deviceService.updateDeviceIsUpload( id);
        return success(BeanUtils.toBean(device, DeviceRespVO.class));
    }




    @GetMapping("/page")
    @Operation(summary = "获得IoT 设备分页")
    @PreAuthorize("@ss.hasPermission('mqtt:device:query')")
    public CommonResult<PageResult<DeviceRespVO>> getDevicePage(@Valid DevicePageReqVO pageReqVO) {
        PageResult<DeviceDO> pageResult = deviceService.getDevicePage(pageReqVO);
        return success(BeanUtils.toBean(pageResult, DeviceRespVO.class));
    }


    @GetMapping("/permissionPage")
    @Operation(summary = "获得IoT 设备分页")
    @PreAuthorize("@ss.hasPermission('mqtt:device:query')")
    public CommonResult<PageResult<DeviceRespVO>> permissionPage(@Valid DevicePageReqVO pageReqVO) {
        PageResult<DeviceDO> pageResult = deviceService.getDevicePermissionPage(pageReqVO);
        List<String> diviceKeyList = new ArrayList<>();
        for (int i = 0; i < pageResult.getList().size(); i++) {
            List<DeviceDO> list = pageResult.getList();
            diviceKeyList.add(list.get(i).getDeviceKey());
        }
        Map<String, DeviceLatestFlowDO> map = new HashMap<>();
        DeviceLatestFlowReqVO reqVO = new DeviceLatestFlowReqVO();
        reqVO.setDeviceKeys(diviceKeyList);
        List<DeviceLatestFlowDO> latestDOList = deviceLatestService.getList(reqVO);
        for (int i = 0; i < latestDOList.size(); i++) {
            map.put(latestDOList.get(i).getDeviceKey(), latestDOList.get(i));
        }
        PageResult<DeviceRespVO> respVO = BeanUtils.toBean(pageResult, DeviceRespVO.class);

        for (int i = 0; i < respVO.getList().size(); i++) {
            DeviceRespVO deviceDO = respVO.getList().get(i);
            if (ObjUtil.isNotEmpty(deviceDO)) {
//                String wd = ObjUtil.isNotEmpty(map.get(deviceDO.getDeviceKey())) ? map.get(deviceDO.getDeviceKey()).getPayloadWd() : "";
//                String zd = ObjUtil.isNotEmpty(map.get(deviceDO.getDeviceKey())) ? map.get(deviceDO.getDeviceKey()).getPayloadZd() : "";
//                String yl = ObjUtil.isNotEmpty(map.get(deviceDO.getDeviceKey())) ? map.get(deviceDO.getDeviceKey()).getPayloadYl() : "";
//                String ph = ObjUtil.isNotEmpty(map.get(deviceDO.getDeviceKey())) ? map.get(deviceDO.getDeviceKey()).getPayloadPh() : "";

//                deviceDO.setWd(wd);
//                deviceDO.setZd(zd);
//                deviceDO.setYl(yl);
//                deviceDO.setPh(ph);
//                respVO.getList().set(i, deviceDO);
            }

        }
        return success(respVO);
    }

    @GetMapping("/mapList")
    @Operation(summary = "地图List")
    @PreAuthorize("@ss.hasPermission('mqtt:device:query')")
    public CommonResult<List<DeviceMapRespVO>> mapList() {
        List<DeviceDO> list = deviceService.getList(new DeviceDO());
        return success(BeanUtils.toBean(list, DeviceMapRespVO.class));
    }


    @GetMapping("/export-excel")
    @Operation(summary = "导出IoT 设备 Excel")
    @PreAuthorize("@ss.hasPermission('mqtt:device:export')")
    @ApiAccessLog(operateType = EXPORT)
    public void exportDeviceExcel(@Valid DevicePageReqVO pageReqVO,
                                  HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<DeviceDO> list = deviceService.getDevicePage(pageReqVO).getList();
        // 导出 Excel
        ExcelUtils.write(response, "IoT 设备.xls", "数据", DeviceRespVO.class,
                BeanUtils.toBean(list, DeviceRespVO.class));
    }

    /**
     * 上传
     * @param file
     * @param deviceId
     * @return
     */
    @PostMapping("/upload")
    public synchronized CommonResult<String> uploadFile(@RequestParam("file") MultipartFile file,
                                                        @RequestParam("deviceId") Long deviceId) {
        String path = deviceService.updateUpload(file, deviceId);
        return success(path);
    }

    /**
     * 小程序上传
     * @param file
     * @param deviceSaveReqVO
     * @return
     */
    @PostMapping("/uploadMini")
    public CommonResult<String> uploadFile(@RequestParam("file") MultipartFile file,
                                           DeviceSaveReqVO deviceSaveReqVO) {
        deviceService.saveByMini(file, deviceSaveReqVO);
        return success("SUCCESS");
    }


    @GetMapping("/image/{picUrl}")
    @PermitAll
    public void getImage(@PathVariable String picUrl, HttpServletResponse response) {
        // 设置响应头
        response.setContentType("image/jpeg"); // 根据图片类型设置
        response.setHeader("Content-Disposition", "inline; filename=" + picUrl);
        // 获取图片路径（这里假设图片存储在本地的某个目录下）
        String imagePath = mqttProperties.getUpload() + File.separator + picUrl;
        // 读取图片并写入响应流
        try (FileInputStream fis = new FileInputStream(imagePath);
             OutputStream os = response.getOutputStream()) {
            byte[] buffer = new byte[1024];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @GetMapping("/qrcode/base64/{deviceId}")
    @Operation(summary = "获取设备二维码（Base64格式）")
    @Parameter(name = "deviceId", description = "设备ID", required = true)
    @PermitAll // 或权限控制：@PreAuthorize("@ss.hasPermission('mqtt:device:qrcode')")
    public CommonResult<Map<String, String>> getDeviceQRCodeBase64(
            @PathVariable("deviceId") Long deviceId) {

        try {
            // 获取data
            String data = deviceService.getOrCreateDeviceKey(deviceId);

            // 使用 deviceKey 生成二维码 Base64
            String base64Image = QRCodeUtil.generateQRCodeBase64(data, 300, 300);

            // 返回结果
            return success(Map.of(
                    "data", data,
                    "qrcode", base64Image
            ));
        } catch (ServiceException e) {
            throw e; // 已知异常直接抛
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @PostMapping("/qrcode/base64/batch")
    @Operation(summary = "批量获取设备二维码（Base64格式）")
    @Parameter(name = "deviceIds", description = "设备ID数组", required = true)
    @PermitAll // 或权限控制：@PreAuthorize("@ss.hasPermission('mqtt:device:qrcode')")
    public CommonResult<List<Map<String, Object>>> getDeviceQRCodeBase64Batch(
            @RequestBody List<Long> deviceIds) {

        try {
            List<Map<String, Object>> result = new ArrayList<>();

            // 循环处理每个设备ID
            for (Long deviceId : deviceIds) {
                // 获取data
                String data = deviceService.getOrCreateDeviceKey(deviceId);

                // 使用 deviceKey 生成二维码 Base64
                String base64Image = QRCodeUtil.generateQRCodeBase64(data, 300, 300);

                // 添加到结果列表
                result.add(Map.of(
                        "deviceId", deviceId,
                        "data", data,
                        "qrcode", base64Image
                ));
            }

            return success(result);
        } catch (ServiceException e) {
            throw e; // 已知异常直接抛
        } catch (Exception e) {
            throw new RuntimeException("批量处理失败: " + e.getMessage(), e);
        }
    }

    /**
     * 立升接口更新 所有的 设备
     *
     * @return
     */
    @PostMapping("/lisUpdateDevice")
    public CommonResult<String> lisUpdateDevice() {
        LisToken lis = LisTreeUtil.getToken();
        LisRes<LisSiteCountVO> res = LisTreeUtil.getCount(LisTreeUtil.countUrl, lis.getAccess_token());
        Log.info("获取设备总数: ---  " + res.getData());
        Integer deviceCount = Integer.parseInt(res.getData().getDeviceCount());
        Integer countTotalPages = LisTreeUtil.calculateTotalPages(deviceCount, 20);
        Log.info("计算发送多少次接口: ---  " + res.getData());
        Integer count = 0;

        // 获取所有设备的Map，以deviceName为key
        Map<String, DeviceDO> map = deviceService.getAllList();

        for (int i = 0; i <= countTotalPages; i++) {
            LisPagesRes<LisSiteContentVO> sites = LisTreeUtil.getSites(LisTreeUtil.sitesUrl, lis.getAccess_token(), 0, 20);
            List<LisSiteContentVO>  contentVOList = sites.getData().getContent();
            for (int j = 0; j < contentVOList.size(); j++) {
                LisSiteContentVO contentVO = contentVOList.get(j);
                String itemId = contentVO.getSiteResources().get(0).getItemId();//设备ID = 网关ID
                String nickName = contentVO.getSiteResources().get(0).getResourceName();
                // 检查设备名称是否已存在（通过Map的key来判断）
                if("浙江省绍兴市新昌县澄谭街道王家坪".equals(contentVO.getSiteName())){
                    Log.info("设备名称已存在: ---  " + contentVO.getSiteName());
                }
                if (ObjectUtil.isNotEmpty(map.get(contentVO.getSiteName()))) {
                    DeviceDO device = map.get(contentVO.getSiteName());
                    device.setDeviceKey(itemId);
                    device.setAddress(contentVO.getSiteAddress());      // 设备地址
                    device.setLatitude(contentVO.getLatitude());        // 设备纬度
                    device.setLongitude(contentVO.getLongitude());      // 设备经度
                    device.setNickname(nickName);
                    device.setProvince(contentVO.getProvince()); //省
                    device.setCity(contentVO.getCity());         //市
                    device.setDistrict(contentVO.getDistrict()); //区
                    deviceService.updateLis(device);
                } else {
                    DeviceSaveReqVO device = new DeviceSaveReqVO();
                    device.setDeviceKey(itemId);                        // key
                    device.setDeviceType("0");                          // 设备类型
                    device.setIsOnline("1");                            // 设备离线状态
                    device.setMqttClientId("1");  //默认服务器1
                    device.setDeviceName(contentVO.getSiteName());
                    device.setAddress(contentVO.getSiteAddress());      // 设备
                    device.setDeviceName(contentVO.getSiteName());
                    device.setLatitude(contentVO.getLatitude());        // 设备纬度
                    device.setLongitude(contentVO.getLongitude());      // 设备经度
                    device.setNickname(nickName);
                    device.setProvince(contentVO.getProvince()); //省
                    device.setCity(contentVO.getCity());         //市
                    device.setDistrict(contentVO.getDistrict()); //区
                    device.setGatewayId(itemId);
                    device.setDataSource("1");
                    deviceService.createDevice(device);
                }
            }
        }
        return success("SUCCESS");
    }


    /**
     * 水量 + 水瞬时流量
     * @return
     */
    @PostMapping("/lisWater")
    public CommonResult<String> lisWater() {
        List<DeviceDO> list = deviceService.getList(new DeviceDO().setIsUpload("1"));
        for (int i = 0; i < list.size(); i++) {
            System.out.println("进度 -- " + i + "/" + list.size());
            DeviceLatestFlowDO waterFlowDO =  deviceLatestService.saveWater(list.get(i)); //水量 累计
            DeviceLatestFlowDO sunFlowDO = deviceLatestService.saveWaterSun(list.get(i));//瞬时
            DeviceLatestFlowDO hourFlowDO = deviceLatestService.saveWaterHourSun(list.get(i));//瞬时
            if(ObjUtil.isNotEmpty(sunFlowDO) || ObjUtil.isNotEmpty(waterFlowDO) ||ObjUtil.isNotEmpty(hourFlowDO)){
                deviceLatestLogService.save(waterFlowDO, sunFlowDO, hourFlowDO);
            }else{
                Log.info("没有数据");
            }
            System.out.println(list.get(i).getDeviceName()+"  -- 已完成");
        }
        return success("SUCCESS");
    }

    /**
     *
     * @param getewayId
     * @return
     */
    @GetMapping("/uploadJCJ")
    @Operation(summary = "上报监测局")
    @Parameter(name = "id", description = "上报监测局", required = true, example = "1024")
    public CommonResult<Integer> uploadInfo(@RequestParam("getewayId") String getewayId) {
        DeviceLatestFlowDO deviceLatestDO = deviceLatestService.getDeviceLatestByGatewayId(getewayId);
        Integer res = deviceLatestService.uploadJCJ(deviceLatestDO, null);
        return success(res);
    }

    /**
     * log上送
     * @param getewayId
     * @return
     */
    @GetMapping("/uploadJCJLog")
    @Operation(summary = "上报监测局")
    @Parameter(name = "id", description = "上报监测局", required = true, example = "1024")
    public CommonResult<Integer> uploadJCJLog(@RequestParam("getewayId") String getewayId) {
        DeviceLatestFlowDO deviceLatestDO = deviceLatestService.getDeviceLatestByGatewayId(getewayId);
        DeviceLatestLogDO logDO = deviceLatestLogService.getDeviceLatestByGatewayId(getewayId);
        Integer res = deviceLatestService.uploadJCJ(deviceLatestDO, logDO.getId());
        return success(res);
    }





    /**
     * 一键上送
     * @param 小时同步流量 + 上送
     * @return
     */
    @GetMapping("/updateHourAndSend")
    @Operation(summary = "小时同步流量 + 上送")
    @Parameter(name = "id", description = "上报监测局", required = true, example = "1024")
    public CommonResult<String> updateHourAndSend() {
        List<DeviceDO> list = deviceService.getList(new DeviceDO().setIsUpload("1"));
        list.forEach(deviceDO -> {
            deviceLatestService.saveWaterHourSun(deviceDO);//小时
            DeviceLatestFlowDO deviceLatestDO = deviceLatestService.getDeviceLatestByGatewayId(deviceDO.getGatewayId());
            deviceLatestService.uploadJCJ(deviceLatestDO, null);
        });
        return success("SUCCESS");
    }


    /**
     * 瞬时流量接收
     * @return
     */
    @PostMapping("/getListMin10")
    public CommonResult<String> getListMin10() {
        LisToken lis = LisTreeUtil.getToken();
        List<DeviceDO> list = deviceService.getList(new DeviceDO());
        return success("SUCCESS");
    }
}